package math

import (
	"jvmgo/instructions/base"
	"jvmgo/rtda"
)

type ISHL struct {
	base.NoOperandsInstruction
}

// Both value1 and value2 must be of type int.
// The values are popped from the operand stack.
// An int result is calculated by shifting value1 left by s bit positions,
// where s is the value of the low 5 bits of value2.
// The result is pushed onto the operand stack.
func (self *ISHL) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := uint32(v2) & 0x1f
	result := v1 << s
	stack.PushInt(result)
}

type ISHR struct {
	base.NoOperandsInstruction
}

func (self *ISHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := uint32(v2) & 0x1f
	result := v1 >> s
	stack.PushInt(result)
}

type IUSHR struct {
	base.NoOperandsInstruction
}

func (self *IUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := uint32(v2) & 0x1f
	result := int32(uint32(v1) >> s)
	stack.PushInt(result)
}

type LSHL struct {
	base.NoOperandsInstruction
}

// The value1 must be of type long, and value2 must be of type int.
// The values are popped from the operand stack.
// A long result is calculated by shifting value1 left by s bit positions,
// where s is the low 6 bits of value2.
// The result is pushed onto the operand stack.
func (self *LSHL) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := v1 << s
	stack.PushLong(result)
}

type LSHR struct {
	base.NoOperandsInstruction
}

func (self *LSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := v1 >> s
	stack.PushLong(result)
}

type LUSHR struct {
	base.NoOperandsInstruction
}

// The value1 must be of type long, and value2 must be of type int.
// The values are popped from the operand stack.
// A long result is calculated by shifting value1 right logically by s bit positions,
// with zero extension, where s is the value of the low 6 bits of value2.
// The result is pushed onto the operand stack.
func (self *LUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := int64(uint64(v1) >> s)
	stack.PushLong(result)
}
